namespace BadHabit.Factory
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Xml.XPath;
    using System.Xml.Xsl;

    /// <summary>
    /// Helps to send notification E-mails.
    /// </summary>
    public class ProjectEmailMessage : System.Net.Mail.MailMessage
    {
        private System.Net.Mail.SmtpClient smtpClient = new System.Net.Mail.SmtpClient();

        public ProjectEmailMessage(string projectUId, string serverPath, string serverUrl)
        {
            try
            {
                this.Project = FactoryLogic.Current.RetriveProjectAndRolesOnly(projectUId);
            }
            catch
            {
            }

            this.ServerPath = serverPath;
            this.ServerUrl = serverUrl;
            this.From = new System.Net.Mail.MailAddress(Properties.Settings.Default.FactoryEmailAccount);
            this.smtpClient.Host = Properties.Settings.Default.SMTPServerAddress;

            this.AdjustProjectDataSet();
        }

        private string DefaultSubject
        {
            get
            {
                if (this.Project == null)
                {
                    return "SCRUM FACTORY - ALERT";
                }

                if (this.Project.Project.Count == 0)
                {
                    return "SCRUM FACTORY - ALERT";
                }

                return this.Project.Project[0].ClientName + " - " + this.Project.Project[0].ProjectName + " [" + this.Project.Project[0].ProjectNumber.ToString("0000") + "]";
            }
        }

        public string ServerPath
        {
            get;
            set;
        }

        /// <summary>
        /// Gets and Sets the server path.
        /// This is used at the XSLT template in order to refer images urls.
        /// </summary>
        public string ServerUrl
        {
            get;
            set;
        }

        /// <summary>
        /// Sets the project used to create the message.
        /// </summary>        
        private Data.ProjectDataSet Project
        {
            get;
            set;
        }

        private void DefineBodyFrom(string templateFullPath)
        {
            if (this.Project == null)
            {
                return;
            }

            System.Xml.Xsl.XslCompiledTransform xslTrans = new XslCompiledTransform();
            xslTrans.Load(templateFullPath);

            // the e-mail message
            this.IsBodyHtml = true;

            this.Project.Namespace = string.Empty;
            XPathDocument xpathDoc = new XPathDocument(new System.IO.StringReader(this.Project.GetXml()));

            StringBuilder sb = new StringBuilder();
            System.IO.StringWriter writer = new System.IO.StringWriter(sb);

            xslTrans.Transform(xpathDoc, null, writer);
            writer.Close();

            Body = writer.ToString();
        }

        private void AdjustProjectDataSet()
        {
            if (this.Project == null)
            {
                return;
            }

            double budgetIndicator = 0.0;
            double qualityIndicator = 0.0;
            double velocityIndicator = 0.0;
            double deadlineIndicator = 0.0;

            try
            {
                Data.ProjectPerformanceDataSet.ProjectPerformanceRow ind = FactoryLogic.Current.RetriveProjectPerformanceIndicators(this.Project.Project[0].ProjectUId);
                if (ind != null)
                {
                    budgetIndicator = ind.PctBudgetBurned;
                    qualityIndicator = ind.PctBugEffort;
                    velocityIndicator = ind.Velocity;
                    deadlineIndicator = ind.HoursAhead;
                }
            }
            catch
            {
            }

            if (!this.Project.Project.Columns.Contains("BudgetIndicator"))
            {
                this.Project.Project.Columns.Add("BudgetIndicator", typeof(double));
            }

            this.Project.Project[0]["BudgetIndicator"] = budgetIndicator;

            if (!this.Project.Project.Columns.Contains("QualityIndicator"))
            {
                this.Project.Project.Columns.Add("QualityIndicator", typeof(double));
            }

            this.Project.Project[0]["QualityIndicator"] = qualityIndicator;

            if (!this.Project.Project.Columns.Contains("VelocityIndicator"))
            {
                this.Project.Project.Columns.Add("VelocityIndicator", typeof(double));
            }

            this.Project.Project[0]["VelocityIndicator"] = velocityIndicator;

            if (!this.Project.Project.Columns.Contains("DeadlineIndicator"))
            {
                this.Project.Project.Columns.Add("DeadlineIndicator", typeof(double));
            }

            this.Project.Project[0]["DeadlineIndicator"] = deadlineIndicator;

            // creates the well-formated date for the XML
            if (!this.Project.Project.Columns.Contains("EstimatedStartDateString"))
            {
                this.Project.Project.Columns.Add("EstimatedStartDateString");
            }

            this.Project.Project[0]["EstimatedStartDateString"] = this.Project.Project[0].EstimatedStartDate.ToShortDateString();

            // creates server path for the XML
            if (!this.Project.Project.Columns.Contains("ServerUrl"))
            {
                this.Project.Project.Columns.Add("ServerUrl");
            }

            this.Project.Project[0]["ServerUrl"] = this.ServerUrl;

            if (!this.Project.Project.Columns.Contains("ClientServerUrl"))
            {
                this.Project.Project.Columns.Add("ClientServerUrl");
            }

            this.Project.Project[0]["ClientServerUrl"] = Properties.Settings.Default.ClientLaunchServerUrl;
        }

        private void DefineSubjectAndDestinatariesForStatusChange()
        {
            if (this.Project == null)
            {
                return;
            }

            string unitFilter = string.Empty;

            switch (this.Project.Project[0].Status)
            {
                case (short)ProjectStatus.PROPOSAL_CREATION:
                    this.Subject = this.DefaultSubject + " - NEW OPORTUNITY";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + ")";
                    break;
                case (short)ProjectStatus.PROPOSAL_APPROVED:
                    this.Subject = this.DefaultSubject + " - PROJECT APPROVED!";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + " OR Type =" + (short)TeamRoles.TEAM + " OR Type =" + (short)TeamRoles.QUALITY_ASSURANCE + ")";
                    break;
                case (short)ProjectStatus.PROPOSAL_REJECTED:
                    this.Subject = this.DefaultSubject + " - PROJECT REJECTED";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + ")";
                    break;
                case (short)ProjectStatus.PROJECT_STARTED:
                    this.Subject = this.DefaultSubject + " - PROJECT STARTED!";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + " OR Type =" + (short)TeamRoles.TEAM + " OR Type =" + (short)TeamRoles.QUALITY_ASSURANCE + ")";
                    break;
                case (short)ProjectStatus.PROJECT_DONE:
                    this.Subject = this.DefaultSubject + " - PROJECT DONE!";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + " OR Type =" + (short)TeamRoles.TEAM + " OR Type =" + (short)TeamRoles.QUALITY_ASSURANCE + ")";
                    break;
                case (short)ProjectStatus.PROJECT_CANCELED:
                    this.Subject = this.DefaultSubject + " - PROJECT CANCELED!";
                    unitFilter = "(Type =" + (short)TeamRoles.COMMERCIAL_GUY + " OR Type=" + (short)TeamRoles.SCRUM_MASTER + " OR Type =" + (short)TeamRoles.TEAM + " OR Type =" + (short)TeamRoles.QUALITY_ASSURANCE + ")";
                    break;
            }

            this.DefineDestinataries(unitFilter);
        }

        private void DefineDestinataries(string unitFilter)
        {
            if (this.Project == null)
            {
                return;
            }

            this.To.Clear();

            foreach (Data.ProjectDataSet.BacklogItemUnitRow unit in this.Project.BacklogItemUnit.Select(unitFilter))
            {
                foreach (Data.ProjectDataSet.ProjectRoleRow r in this.Project.ProjectRole.Select("UnitName='" + unit.UnitName + "'"))
                {
                    string emailAccount = this.FormatEmailAccount(r);

                    if (!string.IsNullOrEmpty(emailAccount))
                    {
                        this.To.Add(emailAccount);
                    }
                }
            }
        }

        /// <summary>
        /// Returns the email account for a given contact.
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private string FormatEmailAccount(Data.ProjectDataSet.ProjectRoleRow c)
        {
            if (!String.IsNullOrEmpty(c.ContactEmail))
            {
                if (!String.IsNullOrEmpty(c.ContactName))
                {
                    return c.ContactName.Replace("\\", "-") + " <" + c.ContactEmail + ">";
                }
                else
                {
                    return c.ContactEmail;
                }
            }

            return string.Empty;
        }

        /// <summary>
        /// Tries to send this message.
        /// </summary>
        /// <returns>True in case of success</returns>
        public void SendStatusChangeNotification()
        {
            if (this.Project == null)
            {
                return;
            }

            this.DefineSubjectAndDestinatariesForStatusChange();

            if (To.Count == 0)
            {
                return;
            }

            this.DefineBodyFrom(this.ServerPath + "\\App_Data\\ProjectEmailTemplates\\Status" + this.Project.Project[0].Status + ".xslt");

            this.smtpClient.Send(this);
        }

        internal void SendNewPlanNotification()
        {
            if (this.Project == null)
            {
                return;
            }

            if (this.Project.Project[0].Baseline == 0)
            {
                return;
            }

            this.DefineSubjectAndDestinatariesForNewPlan();

            if (this.To.Count == 0)
            {
                return;
            }

            this.DefineBodyFrom(this.ServerPath + "\\App_Data\\ProjectEmailTemplates\\NewPlan.xslt");

            this.smtpClient.Send(this);
        }

        internal void SendNewMemberNotification(Data.ProjectDataSet.ProjectRoleRow[] newMembers)
        {
            if (this.Project == null)
            {
                return;
            }

            this.DefineSubjectAndDestinatariesForNewMember(newMembers);

            if (this.To.Count == 0)
            {
                return;
            }

            this.DefineBodyFrom(this.ServerPath + "\\App_Data\\ProjectEmailTemplates\\NewMember.xslt");

            this.smtpClient.Send(this);
        }

        private void DefineSubjectAndDestinatariesForNewPlan()
        {
            if (this.Project == null)
            {
                return;
            }

            this.Subject = this.DefaultSubject + " - SPRINT PLAN " + this.Project.Project[0].Baseline;
            string unitFilter = "(Type=" + (short)TeamRoles.SCRUM_MASTER + " OR Type =" + (short)TeamRoles.TEAM + " OR Type =" + (short)TeamRoles.QUALITY_ASSURANCE + ")";

            this.DefineDestinataries(unitFilter);
        }

        private void DefineSubjectAndDestinatariesForNewMember(Data.ProjectDataSet.ProjectRoleRow[] newMembers)
        {
            if (this.Project == null)
            {
                return;
            }

            this.Subject = this.DefaultSubject + " - NEW MEMBER";

            this.To.Clear();
            foreach (Data.ProjectDataSet.ProjectRoleRow r in newMembers)
            {
                Data.ProjectDataSet.BacklogItemUnitRow unit = this.Project.BacklogItemUnit.FindByUnitNameProjectUId(r.UnitName, this.Project.Project[0].ProjectUId);

                if (unit != null && unit.Type != (short)TeamRoles.CLIENT_CONTACT)
                {
                    string emailAccount = this.FormatEmailAccount(r);

                    if (!String.IsNullOrEmpty(emailAccount))
                    {
                        To.Add(emailAccount);
                    }
                }
            }
        }
    }
}
